/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.group;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.vos.datalist.ListHeaderVo;
import cn.easyplatform.messages.vos.datalist.ListVo;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.support.CellCreater;
import cn.easyplatform.web.task.support.SupportFactory;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.Treerow;

import java.util.Collection;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class LevelGroup extends Group {

    private Multimap<String, Treeitem> map;

    private Multimap<String, Treeitem> pendingMap;

    /**
     * @param support
     * @param support
     * @param listVo
     * @param fields
     */
    public LevelGroup(ListSupport support, ListVo listVo, String[] fields) {
        super(support, listVo, fields);
        rootNode = new Treechildren();
        map = ArrayListMultimap.create();
        pendingMap = ArrayListMultimap.create();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Component> T createGroup(ResultHelper rh,
                                               Map<String, Object> evalMap,
                                               Map<String, Component> managedComponents, int showLevel) {
        ListRowVo lv = rh.item();
        Treerow tr = new Treerow();
        setIndex(false);// 往上累加
        int offset = 0;
        if (support.getEntity().isShowRowNumbers()) {
            offset++;
            Treecell label = new Treecell(String.valueOf(index));
            label.setParent(tr);
        }
        Treeitem ti = new Treeitem();
        ti.setValue(lv);
        Object[] data = lv.getData();
        CellCreater creater = SupportFactory.getCellCreater(support);
        for (int i = 0; i < data.length; i++) {
            ListHeaderVo hv = headers.get(i + offset);
            evalMap.put(hv.getName(), data[i]);
            if (hv.isTotal() && data[i] != null)
                hv.caculate(data[i].toString());
            Component c = creater.createCell(ti, managedComponents, hv, lv, i);
//            if (c.getFirstChild() == null)
//                managedComponents.put(hv.getName(), c);
//            else
//                managedComponents.put(hv.getName(), c.getFirstChild());
            tr.appendChild(c);
        }
        tr.setParent(ti);
        String key = data[fieldIndexs[1]] == null ? "" : data[fieldIndexs[1]]
                .toString();
        Collection<Treeitem> parents = map.get(key);
        if (parents.isEmpty()) {
            if (Strings.isBlank(key))
                ti.setParent(rootNode);
            else
                pendingMap.put(key, ti);
            map.put(data[fieldIndexs[0]] == null ? "" : data[fieldIndexs[0]]
                    .toString(), ti);
        } else if (parents.size() == 1) {
            Treeitem parent = parents.iterator().next();
            if (parent.getFirstChild().getNextSibling() == null) {
                Treechildren tc = new Treechildren();
                tc.setParent(parent);
                ti.setParent(tc);
            } else {
                ti.setParent(parent.getFirstChild().getNextSibling());
            }
            map.put(data[fieldIndexs[0]] == null ? "" : data[fieldIndexs[0]]
                    .toString(), ti);
        } else {
            for (Treeitem parent : parents) {
                ti = (Treeitem) ti.clone();
                if (parent.getFirstChild().getNextSibling() == null) {
                    Treechildren tc = new Treechildren();
                    tc.setParent(parent);
                    ti.setParent(tc);
                } else {
                    ti.setParent(parent.getFirstChild().getNextSibling());
                }
                map.put(data[fieldIndexs[0]] == null ? "" : data[fieldIndexs[0]]
                        .toString(), ti);
            }
        }
        if (!rh.hasNext()) {
            for (Map.Entry<String, Treeitem> entry : pendingMap.entries()) {
                parents = map.get(entry.getKey());
                if (parents.isEmpty()) {
                    entry.getValue().setParent(rootNode);
                } else {
                    parents.forEach(parent -> {
                        if (parent.getFirstChild().getNextSibling() == null) {
                            Treechildren tc = new Treechildren();
                            tc.setParent(parent);
                            entry.getValue().setParent(tc);
                        } else {
                            try {
                                entry.getValue().setParent(
                                        parent.getFirstChild().getNextSibling());
                            } catch (UiException ex) {
                                entry.getValue().setParent(rootNode);
                            }
                        }
                    });
                }
            }
            map.clear();
            pendingMap.clear();
        }
        managedComponents.put("self", ti);
        return (T) ti;
    }

    public void createRow(Treeitem ti, ListRowVo rv,
                          Map<String, Object> evalMap,
                          Map<String, Component> managedComponents) {
        Treerow tr = new Treerow();
        setIndex(false);// 往上累加
        int offset = 0;
        if (support.getEntity().isShowRowNumbers()) {
            offset++;
            Treecell label = new Treecell(String.valueOf(index));
            label.setParent(tr);
        }
        Object[] data = rv.getData();
        CellCreater creater = SupportFactory.getCellCreater(support);
        for (int i = 0; i < data.length; i++) {
            ListHeaderVo hv = headers.get(i + offset);
            evalMap.put(hv.getName(), data[i]);
            if (hv.isTotal() && data[i] != null)
                hv.caculate(data[i].toString());
            Component c = creater.createCell(ti, managedComponents, hv, rv, i);
//            if (c.getFirstChild() == null)
//                managedComponents.put(hv.getName(), c);
//            else
//                managedComponents.put(hv.getName(), c.getFirstChild());
            tr.appendChild(c);
        }
        tr.setParent(ti);
        managedComponents.put("self", ti);
    }

    @Override
    public void clear() {
        super.clear();
        map.clear();
        pendingMap.clear();
        /**
         * clear会导致
         * org.zkoss.zk.ui.WrongValueException: non-negative only
         * 	at org.zkoss.zul.Paging.setTotalSize(Paging.java:100) ~[zul-9.0.0-Eval.jar:9.0.0]
         * 	at org.zkoss.zul.Tree.addVisibleItemCount(Tree.java:332) ~[zul-9.0.0-Eval.jar:9.0.0]
         * 	at org.zkoss.zul.Treechildren.addVisibleItemCount(Treechildren.java:170) ~[zul-9.0.0-Eval.jar:9.0.0]
         * 	at org.zkoss.zul.Treechildren.onChildRemoved(Treechildren.java:159) ~[zul-9.0.0-Eval.jar:9.0.0]
         * 	at org.zkoss.zk.ui.AbstractComponent.removeChild(AbstractComponent.java:1661) ~[classes/:9.0.0]
         * 	at org.zkoss.zk.ui.AbstractComponent$ChildIter.remove(AbstractComponent.java:3536) ~[classes/:9.0.0]
         * 	at java.util.AbstractList.removeRange(AbstractList.java:571) ~[?:1.8.0_201]
         * 	at java.util.AbstractList.clear(AbstractList.java:234) ~[?:1.8.0_201]
         * 	at cn.easyplatform.web.task.zkex.list.group.LevelGroup.clear(LevelGroup.java:151) ~[classes/:?]
         */
        try {
            this.rootNode.getChildren().clear();
        } catch (Exception e) {
        }
    }

}
